#include "ble_discovery.h"
#include <QDebug>
#include <QDateTime>


ble_discovery::ble_discovery(QString devName)
{
    deviceName = devName;

    controller  = NULL;

    pTimer      = NULL;

    m_state     = false;
    m_curSelect = 0;

    // Create a discovery agent and connect to its signals
    discoveryAgent = new QBluetoothDeviceDiscoveryAgent();

    connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
                this, SLOT(devDiscovered(QBluetoothDeviceInfo)));

    connect(discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)),
                this, SLOT(deviceScanError(QBluetoothDeviceDiscoveryAgent::Error)));

    // Start a discovery
    discoveryAgent->start();

    pTimer = new QTimer(this);
    connect(pTimer, &QTimer::timeout, this, &ble_discovery::demons);
    pTimer->start(5000);
}

ble_discovery::~ble_discovery()
{
    delete discoveryAgent;
}

//设备扫描
void ble_discovery::devDiscovered(QBluetoothDeviceInfo info)
{
    if (deviceName.trimmed() == info.name().trimmed())
    {
        if (controller == NULL)
        {
            deviceMac = info.address().toString();

            emit appendInfo("找到设备" + info.name() + deviceMac + "\n");
            qDebug() << "连接服务" << info.name() << deviceMac;

            controller = new QLowEnergyController(info);

            connect(controller, SIGNAL(connected()),
                    this, SLOT(deviceConnected()));
            connect(controller, SIGNAL(error(QLowEnergyController::Error)),
                    this, SLOT(errorReceived(QLowEnergyController::Error)));
            connect(controller, SIGNAL(disconnected()),
                    this, SLOT(deviceDisconnected()));
            connect(controller, SIGNAL(serviceDiscovered(QBluetoothUuid)),
                    this, SLOT(lowEnergyService(QBluetoothUuid)));

            controller->connectToDevice();
        }
    }

//    if (info.name().trimmed().length() > 0)
//    {
//        emit appendInfo(info.name() + "\n");
//        qDebug() << info.name();
//    }
}

void ble_discovery::demons()
{
    if (controller == NULL)
    {
        // Start a discovery
        discoveryAgent->start();
    }
}

void ble_discovery::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error error)
{
    QString errStr;
    if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError)
        errStr = "The Bluetooth adaptor is powered off, power it on before doing discovery.";
    else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError)
        errStr = "Writing or reading from the device resulted in an error.";
    else
        errStr = "An unknown error has occurred.";

    appendInfo(errStr);
    qDebug() << errStr;
}

void ble_discovery::deviceConnected()
{
    if (controller)
    {
        controller->discoverServices();

        emit appendInfo("设备连接成功\n");
        qDebug() << "设备连接成功\n";
    }
}

void ble_discovery::errorReceived(QLowEnergyController::Error)
{
    if (controller)
    {
        appendInfo(controller->errorString());
        qDebug() << controller->errorString();

        emit appendInfo("重新扫描\n");
        qDebug() << "重新扫描\n";
    }
}

void ble_discovery::deviceDisconnected()
{
    if (m_service)
    {
        delete m_service;
        m_service = NULL;
    }

    if (controller)
    {
        delete controller;
        controller = NULL;
    }

    // Start a discovery
    discoveryAgent->start();

    pTimer->start();

    emit appendInfo("设备断开\n");
    qDebug() << "设备断开\n";

    m_state = false;
    emit stateChanged();
}

void ble_discovery::lowEnergyService(const QBluetoothUuid &serviceUuid)
{
    //判断服务的UID，是否是需要控制的ID
    if (serviceUuid.toUInt32() == 0xFFE0)
    {
        QLowEnergyService *service = controller->createServiceObject(serviceUuid);
        if (!service) {
            qDebug() << "Cannot create service for uuid";
            return;
        }
        m_service = service;

        connect(service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)),
                this, SLOT(serviceDetailsDiscovered(QLowEnergyService::ServiceState)));
        connect(service, SIGNAL(characteristicRead(const QLowEnergyCharacteristic, const QByteArray)),
                this, SLOT(characteristicRead(const QLowEnergyCharacteristic, const QByteArray)));
        m_service->discoverDetails();

        appendInfo("连接服务\n");
        qDebug() << "连接服务";
    }
}


void ble_discovery::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
{
    if (newState != QLowEnergyService::ServiceDiscovered) {
        // do not hang in "Scanning for characteristics" mode forever
        // in case the service discovery failed
        // We have to queue the signal up to give UI time to even enter
        // the above mode
//        if (newState != QLowEnergyService::DiscoveringServices) {
//            QMetaObject::invokeMethod(this, "characteristicsUpdated",
//                                      Qt::QueuedConnection);
//        }
//        return;
    }

    if (!m_service)
        return;

    QBluetoothUuid uuid((quint32)0xFFE1);
    m_character = m_service->characteristic(uuid);

    if (m_character.isValid())
    {
        m_service->readCharacteristic(m_character);
    }
}

void ble_discovery::setValue(int val)
{
    if (!m_service)
        return;

    if (m_character.isValid())
    {
        QByteArray arr;
        arr.append(val);
        m_service->writeCharacteristic(m_character, arr);

        m_curSelect = val;
    }

    appendInfo(QString("设置参数val=%1\n").arg(val));
    qDebug() << QString("设置参数val=%1\n").arg(val);
}

void ble_discovery::characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
    if (characteristic.isValid())
    {
        m_curSelect = value.data()[0];
        emit curSelectChanged();

        appendInfo("连接特征符\n");
        qDebug() << "连接特征符";

        m_state = true;
        emit stateChanged();
    }
}
